using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Windows.Forms;
using CodePlex.DnD4eCampaignManager.ControlLibrary;
using CodePlex.DnD4eCampaignManager.DnD4e;
using CodePlex.DnD4eCampaignManager.DnD4e.Interfaces;
using CodePlex.DnD4eCampaignManager.Presentation;
using CodePlex.DnD4eCampaignManager.Presentation.ViewInterfaces;
using CodePlex.DnD4eCampaignManager.Repositories;

namespace CodePlex.DnD4eCampaignManager.CampaignManagerControlLibrary
{
    public partial class CombatEncounterControl : UserControl, ICombatEncounterView
    {
        private readonly Font _characterFont;
        private readonly Font _monsterFont;
        private Bitmap _activeLineBitmap;

        private ICombatant _currentMonster; //index used for active combatant
        private int _lastCombatantSelected; //index used for selected combatant

        public CombatEncounterControl(IPlayerCharacterRepository playerCharacterRepository, IMonsterRepository monsterRepository)
        {
            //Initialize private members
            _currentMonster = null;
            _lastCombatantSelected = -1;

            InitializeComponent();
            if ( CombatantsList != null )
            {
                _monsterFont = new Font(CombatantsList.Font.FontFamily, CombatantsList.Font.Size, FontStyle.Italic);
                _characterFont = new Font(CombatantsList.Font.FontFamily, CombatantsList.Font.Size, FontStyle.Bold);
                LoadActiveLineBitmap();
            }

            Presenter = new CombatEncounterPresenter(this, playerCharacterRepository, monsterRepository);
            Presenter.DisplayAvailableMonsters();
            Presenter.DisplayAvailablePlayerCharacters();
        }

        public ICombatant[] AvailableMonsters
        {
            set
            {
                AvailableMonstersList.Items.Clear();
                AvailableMonstersList.Items.AddRange(value);
                if ( AvailableMonstersList.Items.Count > 0 )
                {
                    AvailableMonstersList.SelectedIndex = 0;
                }
            }
        }

        public ICombatant[] Combatants
        {
            set
            {
                CombatantsList_TestSelectionRedraw();
                int ctrlCount = CombatantsList.Items.Count;
                int newCount = value.Length;
                for ( int i = 0; i < newCount; i++ )
                {
                    if ( i < ctrlCount )
                    {
                        CombatantsList.Items[i] = value[i];
/*
                        if ( ((ICombatant)CombatantsList.Items[i]).FormatCombatantForDisplay() !=Presenter.FormatCombatantForDisplay(value[i]) )
                        {
                            // when the object doesn't change the data inside might
                            //    this forces an update to the line when the display
                            //    changes for the row.
                            CombatantsList.Invalidate(CombatantsList.GetItemRectangle(i));
                        }
*/
                    }
                    else
                    {
                        CombatantsList.Items.Add(value[i]);
                    }
                }

                while ( newCount < ctrlCount )
                {
                    CombatantsList.Items.RemoveAt(newCount);
                    newCount++;
                }

                CombatantsList_TestSelectionRedraw();
            }
        }

        public string CombatantSelectedInList
        {
            get { return ( (ICombatant) CombatantsList.SelectedItem ).Name; }
            set
            {
                foreach ( ICombatant combatant in CombatantsList.Items )
                {
                    if ( combatant.Name == value )
                    {
                        CombatantsList.SelectedItem = combatant;
                        return;
                    }
                }
            }
        }


        public ICombatant CurrentCombatant
        {
            set
            {
                if ( value != null )
                {
                    ICombatant oldCombatant = _currentMonster;
                    _currentMonster = value;

                    for ( int i = 0; i < CombatantsList.Items.Count; i++ )
                    {
                        if ( ( ( CombatantsList.Items[i] ) == _currentMonster ) ||
                             ( ( CombatantsList.Items[i] ) == oldCombatant ) )
                        {
                            CombatantsList.Invalidate(CombatantsList.GetItemRectangle(i));
                        }
                    }
                }
            }
        }

        public string NewCombatantName
        {
            get { return ModalStringPicker.GetString("Create New Combatant", "Enter the new combatant name:", string.Empty, 500); }
        }

        public IMonster SelectedAvailableMonster
        {
            get { return AvailableMonstersList.SelectedItem as IMonster; }
        }

        public ICombatant SelectedCombatant
        {
            get { return (ICombatant) CombatantsList.SelectedItem; }
            set
            {
                CombatantsList_TestSelectionRedraw();
                ICombatant current = CombatantsList.SelectedItem as ICombatant;
                if ( current != value )
                {
                    //Only want to reset the visual selection when not redundant 
                    // since this triggers updates which add to flickering.
                    CombatantsList.SelectedItem = value;
                }
            }
        }

        public string SelectedCombatantAttackPowers
        {
            get { return SelectedCombatantAttackPowersTextbox.Text; }
            set { SelectedCombatantAttackPowersTextbox.Text = value; }
        }

        public string SelectedCombatantConditions
        {
            get { return SelectedCombatantContitionsTextbox.Text; }
            set { SelectedCombatantContitionsTextbox.Text = value; }
        }

        public int SelectedCombatantCurrentHealingSurges
        {
            get { return Convert.ToInt32((decimal) SelectedCombatantCurrentSurgesNumeric.Value); }
            set { SelectedCombatantCurrentSurgesNumeric.Value = value; }
        }

        public int SelectedCombatantCurrentHitPoints
        {
            get { return Convert.ToInt32((decimal) SelectedCombatantCurrentHitPointsNumeric.Value); }
            set { SelectedCombatantCurrentHitPointsNumeric.Value = value; }
        }

        public bool SelectedCombatantDisplayEnabled
        {
            set
            {
                SelectedCombatantGroupbox.Enabled = value;
                RemoveCombatant.Enabled = value;
            }
        }

        public int SelectedCombatantInitiativeScore
        {
            get { return Convert.ToInt32((decimal) SelectedCombatantInitiativeNumeric.Value); }
            set { SelectedCombatantInitiativeNumeric.Value = value; }
        }

        public string SelectedCombatantName
        {
            set { SelectedCombatantGroupbox.Text = value; }
        }

        public string SelectedCombatantSpecialQualities
        {
            get { return SelectedCombatantSpecialQualitiesTextbox.Text; }
            set { SelectedCombatantSpecialQualitiesTextbox.Text = value; }
        }

        public string SelectedCombatantTactics
        {
            get { return SelectedCombatantTacticsTextbox.Text; }
            set { SelectedCombatantTacticsTextbox.Text = value; }
        }

        public int SelectedCombatantTemporaryHitPoints
        {
            get { return Convert.ToInt32((decimal) SelectedCombatantTemporaryHitPointsNumeric.Value); }
            set { SelectedCombatantTemporaryHitPointsNumeric.Value = value; }
        }

        public int TotalCombatants
        {
            get { return CombatantsList.Items.Count; }
        }

        private CombatEncounterPresenter Presenter { get; set; }

        public void DeselectCombatant()
        {
            CombatantsList.SelectedIndex = -1;
        }

        private void CombatantsList_TestSelectionRedraw()
        {
            if ( ( _lastCombatantSelected >= 0 ) &&
                 ( _lastCombatantSelected != CombatantsList.SelectedIndex ) )
            {
                if ( _lastCombatantSelected < CombatantsList.Items.Count )
                {
                    // force an update to change the brush
                    //  to the appropriate non-selected color
                    CombatantsList.Invalidate(CombatantsList.GetItemRectangle(_lastCombatantSelected));
                }
            }
            _lastCombatantSelected = CombatantsList.SelectedIndex;
        }

        private void LoadActiveLineBitmap()
        {
            try
            {
                Assembly assembly = Assembly.GetExecutingAssembly();
                Stream resourceStream = assembly.GetManifestResourceStream("CodePlex.DnD4eCampaignManager.ControlLibrary.Resources.4.gif");
                if ( resourceStream != null )
                {
                    Bitmap bm = new Bitmap(resourceStream);
                    _activeLineBitmap = bm;
                }
            }
            catch
            {
                Debug.WriteLine("No BitMap");
            }
        }

        private void AddCombatantButton_Click(object sender, EventArgs e)
        {
            LoadActiveLineBitmap();
            Presenter.AddMonster();
        }

        private void AddMultiple_Click(object sender, EventArgs e)
        {
            Presenter.AddMultipleMonsters(
                Convert.ToInt32(ModalNumberPicker.GetNumber("Add Multiple Monsters",
                                                            string.Format("Enter the number of {0}s to add:", SelectedAvailableMonster.DisplayName),
                                                            1, 50, 1, 400)));
        }

        private void AddMultipleSameInit_Click(object sender, EventArgs e)
        {
            Presenter.AddMultipleMonstersWithSameInitiative(
                Convert.ToInt32(ModalNumberPicker.GetNumber("Add Multiple Monsters (with the same Initiative)",
                                                            string.Format("Enter the number of {0}s to add:", SelectedAvailableMonster.DisplayName),
                                                            1, 50, 1, 400)));
        }


        private void CombatantsList_DrawItem(object sender, DrawItemEventArgs e)
        {
            e.DrawBackground();
            if ( e.Index >= 0 )
            {
                Brush brush = null;
                Font font = null;
                Rectangle textBounds = e.Bounds;
                ICombatant combatant = (ICombatant) CombatantsList.Items[e.Index];
                if ( typeof ( PlayerCharacter ) == combatant.GetType() )
                {
                    font = _characterFont;
                    brush = Brushes.Blue;
                }
                else if ( typeof ( Monster ) == combatant.GetType() )
                {
                    font = _monsterFont;
                    brush = Brushes.DarkGreen;
                }
                if ( ( (ListBox) sender ).SelectedIndex == e.Index )
                {
                    brush = Brushes.WhiteSmoke;
                }
                else if ( combatant.IsBloodied )
                {
                    brush = Brushes.Red;
                }
                else if ( combatant.HitPointsCurrent <= 0 )
                {
                    brush = Brushes.Black;
                }
                if ( _activeLineBitmap != null )
                {
                    if ( combatant == _currentMonster )
                    {
                        e.Graphics.DrawImage(_activeLineBitmap, new Rectangle(e.Bounds.X + 2, e.Bounds.Y, e.Bounds.Height, e.Bounds.Height));
                    }

                    textBounds = new Rectangle(e.Bounds.X + ( e.Bounds.Height + 4 ), e.Bounds.Y, e.Bounds.Width - ( e.Bounds.Height + 4 ),
                                               e.Bounds.Height);
                }

                e.Graphics.DrawString(combatant.FormatCombatantForDisplay(), font, brush, textBounds, StringFormat.GenericDefault);
            }
            e.DrawFocusRectangle();
        }

        private void CombatantsList_Format(object sender, ListControlConvertEventArgs e)
        {
            e.Value = ( (ICombatant) e.ListItem ).FormatCombatantForDisplay();
        }

        private void CombatantsList_MouseDown(object sender, MouseEventArgs e)
        {
            if ( e.Button == MouseButtons.Left )
            {
                CombatantsList_TestSelectionRedraw();
            }
        }

        private void CombatantsList_MouseMove(object sender, MouseEventArgs e)
        {
            if ( e.Button == MouseButtons.Left )
            {
                CombatantsList_TestSelectionRedraw();
            }
        }

        private void CombatantsList_SelectedIndexChanged(object sender, EventArgs e)
        {
            Presenter.SelectCombatant();
        }

        private void DamageCombatant_Click(object sender, EventArgs e)
        {
            Presenter.DamageCurrentCombatant(
                Convert.ToInt32(ModalNumberPicker.GetNumber("Damage", "Enter the number of Hit Points of damage:", 0, 250, 0, 318)));
        }

        private void HealCombatant_Click(object sender, EventArgs e)
        {
            Presenter.HealCurrentCombatant(
                Convert.ToInt32(ModalNumberPicker.GetNumber("Heal", "Enter the number of Hit Points of healing:", 0, 250, 0, 314)));
        }

        private void NextCombatant_Click(object sender, EventArgs e)
        {
            Presenter.AdvanceCombatToNextCombatant();
        }

        private void RemoveCombatant_Click(object sender, EventArgs e)
        {
            Presenter.RemoveSelectedCombatant();
        }

        private void SpendHealingSurge_Click(object sender, EventArgs e)
        {
            Presenter.SpendHealingSurge();
        }
    }
}